source R profile. Memory was set to 500000.

Sys.setenv("R_ENVIRON_USER"='/Users/castilln/.Renviron')
Sys.getenv("R_ENVIRON_USER")
[1] "/Users/castilln/.Renviron"

Load expression data & spliceosome data

CCLE_expression <- fread("/Users/castilln/Desktop/thesis/localdata/depmap/CCLE_expression.csv", header = TRUE) 
#rows: tumor sample barcode
#column: genes
#values: expression (TPM) already log2 transformed

sample_info <- read_csv("/Users/castilln/Desktop/thesis/localdata/depmap/sample_info.csv") #metadata

── Column specification ──────────────────────────────────────────────────────────────────────────────────────
cols(
  .default = col_character(),
  COSMICID = col_double(),
  Achilles_n_replicates = col_double(),
  cell_line_NNMD = col_double(),
  cas9_activity = col_double(),
  WTSI_Master_Cell_ID = col_double(),
  age = col_double(),
  depmap_public_comments = col_logical()
)
ℹ Use `spec()` for the full column specifications.

11 parsing failures.
 row                    col           expected                                     actual                                                              file
1105 depmap_public_comments 1/0/T/F/TRUE/FALSE Adherent version of CCLFPEDS0001T          '/Users/castilln/Desktop/thesis/localdata/depmap/sample_info.csv'
1166 depmap_public_comments 1/0/T/F/TRUE/FALSE SV40+TERT immortalized kidney cell line    '/Users/castilln/Desktop/thesis/localdata/depmap/sample_info.csv'
1455 depmap_public_comments 1/0/T/F/TRUE/FALSE Drug resistance: Dabrafenib and Trametinib '/Users/castilln/Desktop/thesis/localdata/depmap/sample_info.csv'
1456 depmap_public_comments 1/0/T/F/TRUE/FALSE Drug resistance: SCH772984                 '/Users/castilln/Desktop/thesis/localdata/depmap/sample_info.csv'
1457 depmap_public_comments 1/0/T/F/TRUE/FALSE Drug resistance: Dabrafenib and Trametinib '/Users/castilln/Desktop/thesis/localdata/depmap/sample_info.csv'
.... ...................... .................. .......................................... .................................................................
See problems(...) for more details.
CCLE_mutations <- fread("/Users/castilln/Desktop/thesis/localdata/depmap/CCLE_info", header = TRUE) #mutations and sample info 
|--------------------------------------------------|
|==================================================|
|--------------------------------------------------|
|==================================================|
mutations_spliceosome = fread("/Users/castilln/Desktop/thesis/localdata/depmap/mutations_spliceosome.csv")

Contingency table - Annotation of cell lines with spliceosome mutations

table(distinct(cell_lines_list_mutated)$primary_disease,distinct(cell_lines_list_mutated)$spliceosome_mutated)
                            
                              NO YES
  Adrenal Cancer               0   1
  Bile Duct Cancer             3  33
  Bladder Cancer               0  39
  Bone Cancer                 10  65
  Brain Cancer                 8  99
  Breast Cancer               16  66
  Cervical Cancer              0  22
  Colon/Colorectal Cancer      4  79
  Embryonal Cancer             0   3
  Endometrial/Uterine Cancer   1  38
  Engineered                   9   5
  Esophageal Cancer            0  38
  Eye Cancer                   0   9
  Fibroblast                   5  38
  Gallbladder Cancer           0   7
  Gastric Cancer               2  47
  Head and Neck Cancer         4  72
  Kidney Cancer                6  50
  Leukemia                     9 123
  Liposarcoma                  0  11
  Liver Cancer                 0  27
  Lung Cancer                 12 261
  Lymphoma                     4 105
  Myeloma                      1  33
  Neuroblastoma                1  45
  Non-Cancerous                2   3
  Ovarian Cancer               5  69
  Pancreatic Cancer            8  51
  Prostate Cancer              0  13
  Rhabdoid                     1  19
  Sarcoma                      7  35
  Skin Cancer                  7 106
  Teratoma                     0   1
  Thyroid Cancer               0  21
  Unknown                      9  36

Differential Expression Analysis

#make sure expression data is normally distributed 
#central limit theorem: sample size large enough to assume normal distribution
CCLE_expression = 
  CCLE_expression %>% 
  rename("DepMap_ID" = "V1")

#join expression data with metadata
long_CCLE_expression =
  CCLE_expression %>%
  pivot_longer(cols=-DepMap_ID, names_to = "Gene", values_to = "TPM") %>% 
  left_join(cell_lines_list_mutated, by = "DepMap_ID")

#Lets see the distribution of the expression data

library(ggdist)
ggplot(long_CCLE_expression, aes(x=TPM)) +
  geom_histogram(aes(y=..density..), position="identity", alpha=0.5) + 
  geom_density(alpha=0.6)

Filter out those genes whose median for expression is lower than 1 across all samples

median_CCLE_expression =
  long_CCLE_expression %>% 
  group_by(Gene) %>% 
  dplyr::mutate(median = median(TPM, na.rm=TRUE)) %>% 
  filter(median >= 1)

Plot again

ggplot(median_CCLE_expression, aes(x=TPM)) +
  geom_histogram(aes(y=..density..), position="identity", alpha=0.5) + 
  geom_density(alpha=0.6)

After joinin with the expression data, let’s see how many cell lines we have mutated or not mutated

median_CCLE_expression = 
  median_CCLE_expression %>% 
  rename("cell_line" = "stripped_cell_line_name")

median_CCLE_expression %>% 
  ungroup() %>% 
  select(primary_disease, cell_line, spliceosome_mutated) %>% 
  distinct() %>% 
  group_by(primary_disease, spliceosome_mutated) %>% 
  tally()

median_CCLE_expression %>% 
  ungroup %>% 
  select(cell_line) %>% 
  distinct() %>% dim()
[1] 1369    1

Let’s keep only those cancers with a relatively significant number of cell lines w/o mutations in the spliceosome:

keep <- c("Bone Cancer", "Pancreatic Cancer", "Leukemia")

df_deseq = 
median_CCLE_expression %>% 
  filter(primary_disease %in% keep)

t-test

#filt_CCLE_expression %>% 
  df_deseq %>% 
  select(DepMap_ID, Gene, TPM, spliceosome_mutated) %>% 
  filter(spliceosome_mutated == "NO") %>% 
  select(c(Gene, TPM))-> no_t_expression

#head(no_t_expression)

#filt_CCLE_expression %>% 
df_deseq %>% 
  select(DepMap_ID, Gene, TPM, spliceosome_mutated) %>% 
  filter(spliceosome_mutated == "YES") %>% 
  select(c(Gene, TPM)) -> yes_t_expression

#head(yes_t_expression)

t.test(no_t_expression$TPM, yes_t_expression$TPM, alternative = "two.sided", var.equal = FALSE)

    Welch Two Sample t-test

data:  no_t_expression$TPM and yes_t_expression$TPM
t = 7.0946, df = 250114, p-value = 1.3e-12
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 0.02553765 0.04503382
sample estimates:
mean of x mean of y 
 4.100692  4.065406 

Create DGElist

A DGElist object conveniently stores count matrix, sample metadata and gene annotation as one object for easy manipulation.

Count matrix

df_counts = df_deseq %>% 
  select(cell_line, Gene, TPM) %>%  
  pivot_wider(names_from = cell_line, values_from = TPM) %>%  
  as.data.frame()

#STORE FIRST COLUMN AS ROWNAMES
rownames(df_counts) = df_counts[,1]

rownames(df_counts) <- gsub("\\s*\\([^\\)]+\\)","",as.character(rownames(df_counts)))

#REMOVE FIRST COLUMN
df_counts = df_counts[,-1]  

##THERE ARE NA VALUES IN DF_COUNTS. SUBSTITUTE NA VALUES BY THE MEAN EXPRESSION FOR THAT CELL LINE
for(i in 1:ncol(df_counts)){
  df_counts[is.na(df_counts[,i]), i] <- mean(df_counts[,i], na.rm = TRUE)
} 
meta = 
  df_deseq %>% 
  ungroup() %>% 
  select(-c("TPM", "median", "Gene")) %>% 
  distinct()

Reorder count columns by meta ID

##REORDER COLUMNS BY SAMPLE INFO
df_counts = df_counts[meta$cell_line]

head(df_counts)

Create grouping factor

meta = 
  meta %>% 
  mutate(group = as.factor(spliceosome_mutated)) %>% 
  select(-spliceosome_mutated) %>% 
  mutate(primary_disease = as.factor(primary_disease))

Create gene annotation

#SOMETIMES PROBLEMS TO LOAD THIS LIBRARIES BECAUSE INCOMPATIBILITIES W/ COMPLEX HEATMAP: START NEW R SESSION
library("AnnotationDbi")
library("org.Hs.eg.db")

gene_annot = AnnotationDbi::mapIds(org.Hs.eg.db, keys = rownames(df_counts),
                                  column = c("GENENAME"), keytype = ("SYMBOL")) %>% 
  as.data.frame()
'select()' returned 1:many mapping between keys and columns
colnames(gene_annot) = c("DESCRIPTION")

Make grouping factor in DGEList

Change primary_disease names to something understandable for R as names

meta$primary_disease = gsub(" ", "_", meta$primary_disease)
meta$primary_disease = gsub("/", "_", meta$primary_disease)
dge = DGEList(counts = df_counts, 
              samples = meta, 
              genes = gene_annot)

summary(dge)
        Length  Class      Mode   
counts  2165430 -none-     numeric
samples       6 data.frame list   
genes         1 data.frame list   

Filtering and pre-process

Filter low expressed genes

#keep  = filterByExpr(dge, group = group)
#dge = dge[keep, , keep.lib.sizes = FALSE]

Calculate library normalization factors

dge <- calcNormFactors(dge)
dge$samples

MDS (multidimensional scaling plot)

plotMDS(dge)

Differential expression

Set up desing matrix

design = model.matrix(~0+group+primary_disease, data = dge$samples)


colnames(design)
[1] "groupNO"                          "groupYES"                         "primary_diseaseLeukemia"         
[4] "primary_diseasePancreatic_Cancer"
#design

Calculate dispersions

dge = estimateDisp(dge, design)
fit <- glmQLFit(dge, design)

plotQLDisp(fit)

In order to compare the difference in cell lines with spliceosome mutations vs wt for all different cancers, we need to define some contrasts for the model.

my.contrasts <- makeContrasts(
  YvsN = `groupYES`-`groupNO`,
  levels = design
)

Now we are going to use the model contrasts to determine pairwise differential expression using the quasi-likelihood (QL)-F-test

qlf.spliceosome.YvsN <- glmQLFTest(fit, contrast=my.contrasts[,"YvsN"])
topTags(qlf.spliceosome.YvsN)
Coefficient:  -1*groupNO 1*groupYES 

Adjust p-values (FDR) and merge data into a single table to facilitate the analysis:

TidyQLF = function(qlf, contrast) {
  df_qlf =
    qlf$table %>%
    as_tibble(rownames = "SYMBOL") %>%
    mutate(FDR = p.adjust(PValue, method = "fdr"))
  
  df_full =
    cbind(qlf$genes,df_qlf) %>% 
    mutate(comparison = contrast) %>%
    relocate(SYMBOL, .before = DESCRIPTION) %>% 
    relocate(comparison, .before = SYMBOL) 
  
  return(df_full)
}


tbl_YvsN = TidyQLF(qlf.spliceosome.YvsN,"YesvsNo")


head(tbl_YvsN)

Exploration using PCA/tSNE

Prepare for tSNE/PCA

##PIVOT WIDER
df_wide = 
  median_CCLE_expression %>% 
  select(DepMap_ID, Gene, TPM, spliceosome_mutated, primary_disease) %>% 
  pivot_wider(names_from = Gene, values_from = TPM) %>%  
  as.data.frame() %>% 
  relocate(DepMap_ID, .after = primary_disease)



expression_pca <- as.matrix(df_wide[,3:11400])
expression <- as.matrix(df_wide[,4:11400])
disease <- df_wide[, 2] #disease
mutated <- df_wide[, 1]

##GET RID OF NA VALUES AND SUBSTITUTE FOR MEAN EXPRESSION PER CELL LINE
for(i in 1:ncol(expression)){
  expression[is.na(expression[,i]), i] <- mean(expression[,i], na.rm = TRUE)
} 

Run PCA

pca1 = prcomp(expression, center = TRUE, scale = TRUE, na.action=na.omit(expression))
In prcomp.default(expression, center = TRUE, scale = TRUE, na.action = na.omit(expression)) :
 extra argument ‘na.action’ will be disregarded
plotData = pca1$x[,1:2]
plotData = cbind(DepMap_ID = expression_pca[,1], plotData)
rownames(plotData) = NULL

head(plotData)
     DepMap_ID    PC1                 PC2                
[1,] "ACH-001113" "-25.8912390948755" "-11.8772754159592"
[2,] "ACH-001289" "-32.089833776787"  "-2.23149492296967"
[3,] "ACH-001339" "15.0538289388188"  "-24.0719270653194"
[4,] "ACH-001538" "25.7704229940894"  "-16.4639435369173"
[5,] "ACH-000242" "-5.39230565201994" "1.88725601590978" 
[6,] "ACH-000708" "10.3601145160347"  "9.1981704143161"  
ID = plotData[,1]

to_join = 
  median_CCLE_expression %>% 
  select(DepMap_ID, primary_disease, spliceosome_mutated)
Adding missing grouping variables: `Gene`
plotData %>% 
  as_tibble() %>% 
  left_join(to_join, by ="DepMap_ID") %>%
  mutate(PC1 = as.double(PC1),
         PC2 = as.double(PC2))  -> plotData_gg

Plot


ggplot(plotData_gg, aes(x = PC1,y = PC2, color = spliceosome_mutated)) +
  geom_point() +
  facet_wrap(vars(primary_disease), scales = "free") + 
  stat_ellipse() -> gg_expression_mutated

ggsave("/Users/castilln/Desktop/thesis/gg_expression_mutated.png", device = "png", width = 35, height = 20, units = "cm", dpi = "retina")
  

ggplot(plotData_gg, aes(x = PC1,y = PC2, color = primary_disease)) +
  geom_point() +
  scale_color_manual(values = c("gainsboro", 'forestgreen', 'red2', 'orange',  'cornflowerblue', 
                'magenta', 'darkolivegreen4',  'indianred1',  'tan4', 'darkblue', 
                'mediumorchid1', 'firebrick4',  'yellowgreen', 'lightsalmon', 'tan3',
                "tan1",  'darkgray','wheat4',  '#DDAD4B',  'chartreuse', 
                 'seagreen1', 'moccasin',   'mediumvioletred', 'seagreen', 'cadetblue1',
                "darkolivegreen1" ,"tan2" ,  "tomato3" , "#7CE3D8", "black", "yellow", "violetred", "blue")) -> gg_expression_disease

  ggsave("/Users/castilln/Desktop/thesis/gg_expression_disease.png", device = "png", width = 25, height = 15, units = "cm", dpi = "retina")

grid.arrange(gg_expression_disease, gg_expression_mutated, ncol = 2)

NA

Run tSNE

LS0tCnRpdGxlOiAiQ0NMRSBleHByZXNzaW9uIGFuYWx5c2lzIHJlbGF0ZWQgdG8gc3BsaWNlb3NvbWFsIG11dGF0aW9ucyIKYXV0aG9yOiAiTGV0aWNpYSBDYXN0aWxsb24iCmRhdGU6ICIyMy0xMS0yMDIwIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShlZGdlUikKbGlicmFyeShkcGx5cikKbGlicmFyeShyZWFkcikKbGlicmFyeShiaW9tYVJ0KQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dzY2kpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeShnZ0V4dHJhKQpsaWJyYXJ5KEtFR0dSRVNUKQpsaWJyYXJ5KGhyYnJ0aGVtZXMpCmxpYnJhcnkod2VzYW5kZXJzb24pCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShSdHNuZSkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZ3JpZEV4dHJhKQpzZWxlY3QgPSBkcGx5cjo6c2VsZWN0CnJlbmFtZSA9IGRwbHlyOjpyZW5hbWUKZmlsdGVyID0gZHBseXI6OmZpbHRlcgpgYGAKCgpzb3VyY2UgUiBwcm9maWxlLiBNZW1vcnkgd2FzIHNldCB0byA1MDAwMDAuCmBgYHtyfQpTeXMuc2V0ZW52KCJSX0VOVklST05fVVNFUiI9Jy9Vc2Vycy9jYXN0aWxsbi8uUmVudmlyb24nKQpTeXMuZ2V0ZW52KCJSX0VOVklST05fVVNFUiIpCgpgYGAKCgojIExvYWQgZXhwcmVzc2lvbiBkYXRhICYgc3BsaWNlb3NvbWUgZGF0YQpgYGB7cn0KQ0NMRV9leHByZXNzaW9uIDwtIGZyZWFkKCIvVXNlcnMvY2FzdGlsbG4vRGVza3RvcC90aGVzaXMvbG9jYWxkYXRhL2RlcG1hcC9DQ0xFX2V4cHJlc3Npb24uY3N2IiwgaGVhZGVyID0gVFJVRSkgCiNyb3dzOiB0dW1vciBzYW1wbGUgYmFyY29kZQojY29sdW1uOiBnZW5lcwojdmFsdWVzOiBleHByZXNzaW9uIChUUE0pIGFscmVhZHkgbG9nMiB0cmFuc2Zvcm1lZAoKc2FtcGxlX2luZm8gPC0gcmVhZF9jc3YoIi9Vc2Vycy9jYXN0aWxsbi9EZXNrdG9wL3RoZXNpcy9sb2NhbGRhdGEvZGVwbWFwL3NhbXBsZV9pbmZvLmNzdiIpICNtZXRhZGF0YQoKQ0NMRV9tdXRhdGlvbnMgPC0gZnJlYWQoIi9Vc2Vycy9jYXN0aWxsbi9EZXNrdG9wL3RoZXNpcy9sb2NhbGRhdGEvZGVwbWFwL0NDTEVfaW5mbyIsIGhlYWRlciA9IFRSVUUpICNtdXRhdGlvbnMgYW5kIHNhbXBsZSBpbmZvIAoKbXV0YXRpb25zX3NwbGljZW9zb21lID0gZnJlYWQoIi9Vc2Vycy9jYXN0aWxsbi9EZXNrdG9wL3RoZXNpcy9sb2NhbGRhdGEvZGVwbWFwL211dGF0aW9uc19zcGxpY2Vvc29tZS5jc3YiKQpgYGAKQ29udGluZ2VuY3kgdGFibGUgLSBBbm5vdGF0aW9uIG9mIGNlbGwgbGluZXMgd2l0aCBzcGxpY2Vvc29tZSBtdXRhdGlvbnMKYGBge3J9CmNlbGxfbGluZXNfbGlzdCA9IAogIENDTEVfbXV0YXRpb25zICU+JSAKICBzZWxlY3Qoc3RyaXBwZWRfY2VsbF9saW5lX25hbWUsIHByaW1hcnlfZGlzZWFzZSwgRGVwTWFwX0lEKSAKCmNlbGxfbGluZXNfbGlzdF9tdXRhdGVkID0gCiBjZWxsX2xpbmVzX2xpc3QgJT4lIAogICBtdXRhdGUoc3BsaWNlb3NvbWVfbXV0YXRlZCA9IAogICAgICAgICAgIGNhc2Vfd2hlbigKICAgICAgICAgICAgY2VsbF9saW5lc19saXN0JHN0cmlwcGVkX2NlbGxfbGluZV9uYW1lICVpbiUgbXV0YXRpb25zX3NwbGljZW9zb21lJHN0cmlwcGVkX2NlbGxfbGluZV9uYW1lIH4gIllFUyIsICNpZiB0aGUgbXV0YXRpb24gaXMgaW4gYSBnZW5lIGZyb20gdGhlIHNwbGljZW9zb21lOiAxIAogICAgICAgICAgICAhY2VsbF9saW5lc19saXN0JHN0cmlwcGVkX2NlbGxfbGluZV9uYW1lICVpbiUgbXV0YXRpb25zX3NwbGljZW9zb21lJHN0cmlwcGVkX2NlbGxfbGluZV9uYW1lIH4gIk5PIikpICU+JSAKICBkaXN0aW5jdCgpCgpjZWxsX2xpbmVzX2xpc3RfbXV0YXRlZCAlPiUgCiAgZGlzdGluY3QoKSAlPiUKICBncm91cF9ieShwcmltYXJ5X2Rpc2Vhc2Usc3BsaWNlb3NvbWVfbXV0YXRlZCkgJT4lCiAgdGFsbHkoKQoKdGFibGUoZGlzdGluY3QoY2VsbF9saW5lc19saXN0X211dGF0ZWQpJHByaW1hcnlfZGlzZWFzZSxkaXN0aW5jdChjZWxsX2xpbmVzX2xpc3RfbXV0YXRlZCkkc3BsaWNlb3NvbWVfbXV0YXRlZCkKCnNwbGljZW9zb21lX211dGF0ZWRfSUQgPSAKICBjZWxsX2xpbmVzX2xpc3RfbXV0YXRlZCAlPiUgCiAgc2VsZWN0KERlcE1hcF9JRCwgc3BsaWNlb3NvbWVfbXV0YXRlZCkgJT4lIAogIGRpc3RpbmN0KCkgCmBgYAoKCiMjIyBEaWZmZXJlbnRpYWwgRXhwcmVzc2lvbiBBbmFseXNpcwpgYGB7cn0KI21ha2Ugc3VyZSBleHByZXNzaW9uIGRhdGEgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgCiNjZW50cmFsIGxpbWl0IHRoZW9yZW06IHNhbXBsZSBzaXplIGxhcmdlIGVub3VnaCB0byBhc3N1bWUgbm9ybWFsIGRpc3RyaWJ1dGlvbgpDQ0xFX2V4cHJlc3Npb24gPSAKICBDQ0xFX2V4cHJlc3Npb24gJT4lIAogIHJlbmFtZSgiRGVwTWFwX0lEIiA9ICJWMSIpCgojam9pbiBleHByZXNzaW9uIGRhdGEgd2l0aCBtZXRhZGF0YQpsb25nX0NDTEVfZXhwcmVzc2lvbiA9CiAgQ0NMRV9leHByZXNzaW9uICU+JQogIHBpdm90X2xvbmdlcihjb2xzPS1EZXBNYXBfSUQsIG5hbWVzX3RvID0gIkdlbmUiLCB2YWx1ZXNfdG8gPSAiVFBNIikgJT4lIAogIGxlZnRfam9pbihjZWxsX2xpbmVzX2xpc3RfbXV0YXRlZCwgYnkgPSAiRGVwTWFwX0lEIikKCmBgYAoKI0xldHMgc2VlIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGV4cHJlc3Npb24gZGF0YQpgYGB7cn0KbGlicmFyeShnZ2Rpc3QpCmdncGxvdChsb25nX0NDTEVfZXhwcmVzc2lvbiwgYWVzKHg9VFBNKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uKSwgcG9zaXRpb249ImlkZW50aXR5IiwgYWxwaGE9MC41KSArIAogIGdlb21fZGVuc2l0eShhbHBoYT0wLjYpCmBgYApGaWx0ZXIgb3V0IHRob3NlIGdlbmVzIHdob3NlIG1lZGlhbiBmb3IgZXhwcmVzc2lvbiBpcyBsb3dlciB0aGFuIDEgYWNyb3NzIGFsbCBzYW1wbGVzCmBgYHtyfQptZWRpYW5fQ0NMRV9leHByZXNzaW9uID0KICBsb25nX0NDTEVfZXhwcmVzc2lvbiAlPiUgCiAgZ3JvdXBfYnkoR2VuZSkgJT4lIAogIGRwbHlyOjptdXRhdGUobWVkaWFuID0gbWVkaWFuKFRQTSwgbmEucm09VFJVRSkpICU+JSAKICBmaWx0ZXIobWVkaWFuID49IDEpCmBgYAoKUGxvdCBhZ2FpbgpgYGB7cn0KZ2dwbG90KG1lZGlhbl9DQ0xFX2V4cHJlc3Npb24sIGFlcyh4PVRQTSkpICsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIHBvc2l0aW9uPSJpZGVudGl0eSIsIGFscGhhPTAuNSkgKyAKICBnZW9tX2RlbnNpdHkoYWxwaGE9MC42KQpgYGAKQWZ0ZXIgam9pbmluIHdpdGggdGhlIGV4cHJlc3Npb24gZGF0YSwgbGV0J3Mgc2VlIGhvdyBtYW55IGNlbGwgbGluZXMgd2UgaGF2ZSBtdXRhdGVkIG9yIG5vdCBtdXRhdGVkCmBgYHtyfQptZWRpYW5fQ0NMRV9leHByZXNzaW9uID0gCiAgbWVkaWFuX0NDTEVfZXhwcmVzc2lvbiAlPiUgCiAgcmVuYW1lKCJjZWxsX2xpbmUiID0gInN0cmlwcGVkX2NlbGxfbGluZV9uYW1lIikKCm1lZGlhbl9DQ0xFX2V4cHJlc3Npb24gJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgc2VsZWN0KHByaW1hcnlfZGlzZWFzZSwgY2VsbF9saW5lLCBzcGxpY2Vvc29tZV9tdXRhdGVkKSAlPiUgCiAgZGlzdGluY3QoKSAlPiUgCiAgZ3JvdXBfYnkocHJpbWFyeV9kaXNlYXNlLCBzcGxpY2Vvc29tZV9tdXRhdGVkKSAlPiUgCiAgdGFsbHkoKQoKbWVkaWFuX0NDTEVfZXhwcmVzc2lvbiAlPiUgCiAgdW5ncm91cCAlPiUgCiAgc2VsZWN0KGNlbGxfbGluZSkgJT4lIAogIGRpc3RpbmN0KCkgJT4lIGRpbSgpCmBgYApMZXQncyBrZWVwIG9ubHkgdGhvc2UgY2FuY2VycyB3aXRoIGEgcmVsYXRpdmVseSBzaWduaWZpY2FudCBudW1iZXIgb2YgY2VsbCBsaW5lcyB3L28gbXV0YXRpb25zIGluIHRoZSBzcGxpY2Vvc29tZTogCgpgYGB7cn0Ka2VlcCA8LSBjKCJCb25lIENhbmNlciIsICJQYW5jcmVhdGljIENhbmNlciIsICJMZXVrZW1pYSIpCgpkZl9kZXNlcSA9IAptZWRpYW5fQ0NMRV9leHByZXNzaW9uICU+JSAKICBmaWx0ZXIocHJpbWFyeV9kaXNlYXNlICVpbiUga2VlcCkKYGBgCgojIHQtdGVzdApgYGB7cn0KI2ZpbHRfQ0NMRV9leHByZXNzaW9uICU+JSAKICBkZl9kZXNlcSAlPiUgCiAgc2VsZWN0KERlcE1hcF9JRCwgR2VuZSwgVFBNLCBzcGxpY2Vvc29tZV9tdXRhdGVkKSAlPiUgCiAgZmlsdGVyKHNwbGljZW9zb21lX211dGF0ZWQgPT0gIk5PIikgJT4lIAogIHNlbGVjdChjKEdlbmUsIFRQTSkpLT4gbm9fdF9leHByZXNzaW9uCgojaGVhZChub190X2V4cHJlc3Npb24pCgojZmlsdF9DQ0xFX2V4cHJlc3Npb24gJT4lIApkZl9kZXNlcSAlPiUgCiAgc2VsZWN0KERlcE1hcF9JRCwgR2VuZSwgVFBNLCBzcGxpY2Vvc29tZV9tdXRhdGVkKSAlPiUgCiAgZmlsdGVyKHNwbGljZW9zb21lX211dGF0ZWQgPT0gIllFUyIpICU+JSAKICBzZWxlY3QoYyhHZW5lLCBUUE0pKSAtPiB5ZXNfdF9leHByZXNzaW9uCgojaGVhZCh5ZXNfdF9leHByZXNzaW9uKQoKdC50ZXN0KG5vX3RfZXhwcmVzc2lvbiRUUE0sIHllc190X2V4cHJlc3Npb24kVFBNLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCB2YXIuZXF1YWwgPSBGQUxTRSkKYGBgCgoKIyBDcmVhdGUgREdFbGlzdApBIERHRWxpc3Qgb2JqZWN0IGNvbnZlbmllbnRseSBzdG9yZXMgY291bnQgbWF0cml4LCBzYW1wbGUgbWV0YWRhdGEgYW5kIGdlbmUgYW5ub3RhdGlvbiBhcyBvbmUgb2JqZWN0IGZvciBlYXN5IG1hbmlwdWxhdGlvbi4KCiMjIENvdW50IG1hdHJpeApgYGB7cn0KZGZfY291bnRzID0gZGZfZGVzZXEgJT4lIAogIHNlbGVjdChjZWxsX2xpbmUsIEdlbmUsIFRQTSkgJT4lICAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY2VsbF9saW5lLCB2YWx1ZXNfZnJvbSA9IFRQTSkgJT4lICAKICBhcy5kYXRhLmZyYW1lKCkKCiNTVE9SRSBGSVJTVCBDT0xVTU4gQVMgUk9XTkFNRVMKcm93bmFtZXMoZGZfY291bnRzKSA9IGRmX2NvdW50c1ssMV0KCnJvd25hbWVzKGRmX2NvdW50cykgPC0gZ3N1YigiXFxzKlxcKFteXFwpXStcXCkiLCIiLGFzLmNoYXJhY3Rlcihyb3duYW1lcyhkZl9jb3VudHMpKSkKCiNSRU1PVkUgRklSU1QgQ09MVU1OCmRmX2NvdW50cyA9IGRmX2NvdW50c1ssLTFdICAKCiMjVEhFUkUgQVJFIE5BIFZBTFVFUyBJTiBERl9DT1VOVFMuIFNVQlNUSVRVVEUgTkEgVkFMVUVTIEJZIFRIRSBNRUFOIEVYUFJFU1NJT04gRk9SIFRIQVQgQ0VMTCBMSU5FCmZvcihpIGluIDE6bmNvbChkZl9jb3VudHMpKXsKICBkZl9jb3VudHNbaXMubmEoZGZfY291bnRzWyxpXSksIGldIDwtIG1lYW4oZGZfY291bnRzWyxpXSwgbmEucm0gPSBUUlVFKQp9IApgYGAKCmBgYHtyfQptZXRhID0gCiAgZGZfZGVzZXEgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgc2VsZWN0KC1jKCJUUE0iLCAibWVkaWFuIiwgIkdlbmUiKSkgJT4lIAogIGRpc3RpbmN0KCkKYGBgCgpSZW9yZGVyIGNvdW50IGNvbHVtbnMgYnkgbWV0YSBJRAoKYGBge3J9CiMjUkVPUkRFUiBDT0xVTU5TIEJZIFNBTVBMRSBJTkZPCmRmX2NvdW50cyA9IGRmX2NvdW50c1ttZXRhJGNlbGxfbGluZV0KCmhlYWQoZGZfY291bnRzKQpgYGAKQ3JlYXRlIGdyb3VwaW5nIGZhY3RvcgoKYGBge3J9Cm1ldGEgPSAKICBtZXRhICU+JSAKICBtdXRhdGUoZ3JvdXAgPSBhcy5mYWN0b3Ioc3BsaWNlb3NvbWVfbXV0YXRlZCkpICU+JSAKICBzZWxlY3QoLXNwbGljZW9zb21lX211dGF0ZWQpICU+JSAKICBtdXRhdGUocHJpbWFyeV9kaXNlYXNlID0gYXMuZmFjdG9yKHByaW1hcnlfZGlzZWFzZSkpCmBgYAogCgpDcmVhdGUgZ2VuZSBhbm5vdGF0aW9uIAoKYGBge3J9CiNTT01FVElNRVMgUFJPQkxFTVMgVE8gTE9BRCBUSElTIExJQlJBUklFUyBCRUNBVVNFIElOQ09NUEFUSUJJTElUSUVTIFcvIENPTVBMRVggSEVBVE1BUDogU1RBUlQgTkVXIFIgU0VTU0lPTgpsaWJyYXJ5KCJBbm5vdGF0aW9uRGJpIikKbGlicmFyeSgib3JnLkhzLmVnLmRiIikKCmdlbmVfYW5ub3QgPSBBbm5vdGF0aW9uRGJpOjptYXBJZHMob3JnLkhzLmVnLmRiLCBrZXlzID0gcm93bmFtZXMoZGZfY291bnRzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHVtbiA9IGMoIkdFTkVOQU1FIiksIGtleXR5cGUgPSAoIlNZTUJPTCIpKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpCgpjb2xuYW1lcyhnZW5lX2Fubm90KSA9IGMoIkRFU0NSSVBUSU9OIikKYGBgCgojIyBNYWtlIGdyb3VwaW5nIGZhY3RvciBpbiBER0VMaXN0CkNoYW5nZSBwcmltYXJ5X2Rpc2Vhc2UgbmFtZXMgdG8gc29tZXRoaW5nIHVuZGVyc3RhbmRhYmxlIGZvciBSIGFzIG5hbWVzCgpgYGB7cn0KbWV0YSRwcmltYXJ5X2Rpc2Vhc2UgPSBnc3ViKCIgIiwgIl8iLCBtZXRhJHByaW1hcnlfZGlzZWFzZSkKbWV0YSRwcmltYXJ5X2Rpc2Vhc2UgPSBnc3ViKCIvIiwgIl8iLCBtZXRhJHByaW1hcnlfZGlzZWFzZSkKYGBgCgoKYGBge3J9CmRnZSA9IERHRUxpc3QoY291bnRzID0gZGZfY291bnRzLCAKICAgICAgICAgICAgICBzYW1wbGVzID0gbWV0YSwgCiAgICAgICAgICAgICAgZ2VuZXMgPSBnZW5lX2Fubm90KQoKc3VtbWFyeShkZ2UpCmBgYAoKIyBGaWx0ZXJpbmcgYW5kIHByZS1wcm9jZXNzCkZpbHRlciBsb3cgZXhwcmVzc2VkIGdlbmVzCgpgYGB7cn0KI2tlZXAgID0gZmlsdGVyQnlFeHByKGRnZSwgZ3JvdXAgPSBncm91cCkKI2RnZSA9IGRnZVtrZWVwLCAsIGtlZXAubGliLnNpemVzID0gRkFMU0VdCmBgYAoKQ2FsY3VsYXRlIGxpYnJhcnkgbm9ybWFsaXphdGlvbiBmYWN0b3JzCgpgYGB7cn0KZGdlIDwtIGNhbGNOb3JtRmFjdG9ycyhkZ2UpCmRnZSRzYW1wbGVzCmBgYAojIE1EUyAobXVsdGlkaW1lbnNpb25hbCBzY2FsaW5nIHBsb3QpCmBgYHtyfQpwbG90TURTKGRnZSkKYGBgCgoKCgojIERpZmZlcmVudGlhbCBleHByZXNzaW9uClNldCB1cCBkZXNpbmcgbWF0cml4CgpgYGB7cn0KZGVzaWduID0gbW9kZWwubWF0cml4KH4wK2dyb3VwK3ByaW1hcnlfZGlzZWFzZSwgZGF0YSA9IGRnZSRzYW1wbGVzKQoKCmNvbG5hbWVzKGRlc2lnbikKI2Rlc2lnbgpgYGAKCkNhbGN1bGF0ZSBkaXNwZXJzaW9ucwoKYGBge3J9CmRnZSA9IGVzdGltYXRlRGlzcChkZ2UsIGRlc2lnbikKYGBgCgpgYGB7cn0KZml0IDwtIGdsbVFMRml0KGRnZSwgZGVzaWduKQoKcGxvdFFMRGlzcChmaXQpCmBgYAoKSW4gb3JkZXIgdG8gY29tcGFyZSB0aGUgZGlmZmVyZW5jZSBpbiBjZWxsIGxpbmVzIHdpdGggc3BsaWNlb3NvbWUgbXV0YXRpb25zIHZzIHd0IGZvciBhbGwgZGlmZmVyZW50IGNhbmNlcnMsIHdlIG5lZWQgdG8gZGVmaW5lIHNvbWUgY29udHJhc3RzIGZvciB0aGUgbW9kZWwuIAoKYGBge3J9Cm15LmNvbnRyYXN0cyA8LSBtYWtlQ29udHJhc3RzKAogIFl2c04gPSBgZ3JvdXBZRVNgLWBncm91cE5PYCwKICBsZXZlbHMgPSBkZXNpZ24KKQpgYGAKCk5vdyB3ZSBhcmUgZ29pbmcgdG8gdXNlIHRoZSBtb2RlbCBjb250cmFzdHMgdG8gZGV0ZXJtaW5lIHBhaXJ3aXNlIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIHVzaW5nIHRoZSBxdWFzaS1saWtlbGlob29kIChRTCktRi10ZXN0CgpgYGB7cn0KcWxmLnNwbGljZW9zb21lLll2c04gPC0gZ2xtUUxGVGVzdChmaXQsIGNvbnRyYXN0PW15LmNvbnRyYXN0c1ssIll2c04iXSkKdG9wVGFncyhxbGYuc3BsaWNlb3NvbWUuWXZzTikKYGBgCgoKQWRqdXN0IHAtdmFsdWVzIChGRFIpIGFuZCBtZXJnZSBkYXRhIGludG8gYSBzaW5nbGUgdGFibGUgdG8gZmFjaWxpdGF0ZSB0aGUgYW5hbHlzaXM6IAoKYGBge3J9ClRpZHlRTEYgPSBmdW5jdGlvbihxbGYsIGNvbnRyYXN0KSB7CiAgZGZfcWxmID0KICAgIHFsZiR0YWJsZSAlPiUKICAgIGFzX3RpYmJsZShyb3duYW1lcyA9ICJTWU1CT0wiKSAlPiUKICAgIG11dGF0ZShGRFIgPSBwLmFkanVzdChQVmFsdWUsIG1ldGhvZCA9ICJmZHIiKSkKICAKICBkZl9mdWxsID0KICAgIGNiaW5kKHFsZiRnZW5lcyxkZl9xbGYpICU+JSAKICAgIG11dGF0ZShjb21wYXJpc29uID0gY29udHJhc3QpICU+JQogICAgcmVsb2NhdGUoU1lNQk9MLCAuYmVmb3JlID0gREVTQ1JJUFRJT04pICU+JSAKICAgIHJlbG9jYXRlKGNvbXBhcmlzb24sIC5iZWZvcmUgPSBTWU1CT0wpIAogIAogIHJldHVybihkZl9mdWxsKQp9CgoKdGJsX1l2c04gPSBUaWR5UUxGKHFsZi5zcGxpY2Vvc29tZS5ZdnNOLCJZZXN2c05vIikKCgpoZWFkKHRibF9ZdnNOKQpgYGAKCgojIyBFeHBsb3JhdGlvbiB1c2luZyBQQ0EvdFNORQoKUHJlcGFyZSBmb3IgdFNORS9QQ0EKCmBgYHtyfQojI1BJVk9UIFdJREVSCmRmX3dpZGUgPSAKICBtZWRpYW5fQ0NMRV9leHByZXNzaW9uICU+JSAKICBzZWxlY3QoRGVwTWFwX0lELCBHZW5lLCBUUE0sIHNwbGljZW9zb21lX211dGF0ZWQsIHByaW1hcnlfZGlzZWFzZSkgJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBHZW5lLCB2YWx1ZXNfZnJvbSA9IFRQTSkgJT4lICAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIHJlbG9jYXRlKERlcE1hcF9JRCwgLmFmdGVyID0gcHJpbWFyeV9kaXNlYXNlKQoKCgpleHByZXNzaW9uX3BjYSA8LSBhcy5tYXRyaXgoZGZfd2lkZVssMzoxMTQwMF0pCmV4cHJlc3Npb24gPC0gYXMubWF0cml4KGRmX3dpZGVbLDQ6MTE0MDBdKQpkaXNlYXNlIDwtIGRmX3dpZGVbLCAyXSAjZGlzZWFzZQptdXRhdGVkIDwtIGRmX3dpZGVbLCAxXQoKIyNHRVQgUklEIE9GIE5BIFZBTFVFUyBBTkQgU1VCU1RJVFVURSBGT1IgTUVBTiBFWFBSRVNTSU9OIFBFUiBDRUxMIExJTkUKZm9yKGkgaW4gMTpuY29sKGV4cHJlc3Npb24pKXsKICBleHByZXNzaW9uW2lzLm5hKGV4cHJlc3Npb25bLGldKSwgaV0gPC0gbWVhbihleHByZXNzaW9uWyxpXSwgbmEucm0gPSBUUlVFKQp9IApgYGAKClJ1biBQQ0EKCmBgYHtyLCAgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9N30KcGNhMSA9IHByY29tcChleHByZXNzaW9uLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IFRSVUUsIG5hLmFjdGlvbj1uYS5vbWl0KGV4cHJlc3Npb24pKQoKcGxvdERhdGEgPSBwY2ExJHhbLDE6Ml0KcGxvdERhdGEgPSBjYmluZChEZXBNYXBfSUQgPSBleHByZXNzaW9uX3BjYVssMV0sIHBsb3REYXRhKQpyb3duYW1lcyhwbG90RGF0YSkgPSBOVUxMCgpoZWFkKHBsb3REYXRhKQoKSUQgPSBwbG90RGF0YVssMV0KCnRvX2pvaW4gPSAKICBtZWRpYW5fQ0NMRV9leHByZXNzaW9uICU+JSAKICBzZWxlY3QoRGVwTWFwX0lELCBwcmltYXJ5X2Rpc2Vhc2UsIHNwbGljZW9zb21lX211dGF0ZWQpCgpwbG90RGF0YSAlPiUgCiAgYXNfdGliYmxlKCkgJT4lIAogIGxlZnRfam9pbih0b19qb2luLCBieSA9IkRlcE1hcF9JRCIpICU+JQogIG11dGF0ZShQQzEgPSBhcy5kb3VibGUoUEMxKSwKICAgICAgICAgUEMyID0gYXMuZG91YmxlKFBDMikpICAtPiBwbG90RGF0YV9nZwpgYGAKUGxvdAoKYGBge3IsICBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xMn0KCmdncGxvdChwbG90RGF0YV9nZywgYWVzKHggPSBQQzEseSA9IFBDMiwgY29sb3IgPSBzcGxpY2Vvc29tZV9tdXRhdGVkKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfd3JhcCh2YXJzKHByaW1hcnlfZGlzZWFzZSksIHNjYWxlcyA9ICJmcmVlIikgKyAKICBzdGF0X2VsbGlwc2UoKSAtPiBnZ19leHByZXNzaW9uX211dGF0ZWQKCmdnc2F2ZSgiL1VzZXJzL2Nhc3RpbGxuL0Rlc2t0b3AvdGhlc2lzL2dnX2V4cHJlc3Npb25fbXV0YXRlZC5wbmciLCBkZXZpY2UgPSAicG5nIiwgd2lkdGggPSAzNSwgaGVpZ2h0ID0gMjAsIHVuaXRzID0gImNtIiwgZHBpID0gInJldGluYSIpCiAgCgpnZ3Bsb3QocGxvdERhdGFfZ2csIGFlcyh4ID0gUEMxLHkgPSBQQzIsIGNvbG9yID0gcHJpbWFyeV9kaXNlYXNlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImdhaW5zYm9ybyIsICdmb3Jlc3RncmVlbicsICdyZWQyJywgJ29yYW5nZScsICAnY29ybmZsb3dlcmJsdWUnLCAKICAgICAgICAgICAgICAgICdtYWdlbnRhJywgJ2RhcmtvbGl2ZWdyZWVuNCcsICAnaW5kaWFucmVkMScsICAndGFuNCcsICdkYXJrYmx1ZScsIAogICAgICAgICAgICAgICAgJ21lZGl1bW9yY2hpZDEnLCAnZmlyZWJyaWNrNCcsICAneWVsbG93Z3JlZW4nLCAnbGlnaHRzYWxtb24nLCAndGFuMycsCiAgICAgICAgICAgICAgICAidGFuMSIsICAnZGFya2dyYXknLCd3aGVhdDQnLCAgJyNEREFENEInLCAgJ2NoYXJ0cmV1c2UnLCAKICAgICAgICAgICAgICAgICAnc2VhZ3JlZW4xJywgJ21vY2Nhc2luJywgICAnbWVkaXVtdmlvbGV0cmVkJywgJ3NlYWdyZWVuJywgJ2NhZGV0Ymx1ZTEnLAogICAgICAgICAgICAgICAgImRhcmtvbGl2ZWdyZWVuMSIgLCJ0YW4yIiAsICAidG9tYXRvMyIgLCAiIzdDRTNEOCIsICJibGFjayIsICJ5ZWxsb3ciLCAidmlvbGV0cmVkIiwgImJsdWUiKSkgLT4gZ2dfZXhwcmVzc2lvbl9kaXNlYXNlCgogIGdnc2F2ZSgiL1VzZXJzL2Nhc3RpbGxuL0Rlc2t0b3AvdGhlc2lzL2dnX2V4cHJlc3Npb25fZGlzZWFzZS5wbmciLCBkZXZpY2UgPSAicG5nIiwgd2lkdGggPSAyNSwgaGVpZ2h0ID0gMTUsIHVuaXRzID0gImNtIiwgZHBpID0gInJldGluYSIpCgpncmlkLmFycmFuZ2UoZ2dfZXhwcmVzc2lvbl9kaXNlYXNlLCBnZ19leHByZXNzaW9uX211dGF0ZWQsIG5jb2wgPSAyKQogIApgYGAKCgpSdW4gdFNORQoKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTV9CnNldC5zZWVkKDYpCnRzbmVfcmVzdWx0cyA8LSBSdHNuZShleHByZXNzaW9uLCBkaW1zID0gMiwgcGVycGxleGl0eSA9IDMwLCB0aGV0YSA9IDAuNSwgY2hlY2tfZHVwbGljYXRlcyA9IEZBTFNFLCBwY2EgPSBUUlVFKQoKI3Bsb3QKCnBsb3REYXRhID0KICB0c25lX3Jlc3VsdHMkWSAlPiUgCiAgYXNfdGliYmxlKCkgJT4lIAogIG11dGF0ZShEZXBNYXBfSUQgPSBJRCkKIApwbG90RGF0YSA9IAogIHBsb3REYXRhICU+JSAKICBsZWZ0X2pvaW4odG9fam9pbiwgYnkgPSJEZXBNYXBfSUQiKSAlPiUgCiAgbXV0YXRlKFYxID0gYXMuZG91YmxlKFYxKSwKICAgICAgICAgVjIgPSBhcy5kb3VibGUoVjIpKQogCnBsb3REYXRhICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBWMSx5ID0gVjIsIGNvbG9yID0gc3BsaWNlb3NvbWVfbXV0YXRlZCkpICsKICBnZW9tX3BvaW50KGFlcyhhbHBoYT0wLjUpLCBzaXplID0gMSkgKwogIHhsYWIoZWxlbWVudF9ibGFuaygpKSArCiAgeWxhYihlbGVtZW50X2JsYW5rKCkpICsKICBmYWNldF93cmFwKHZhcnMocHJpbWFyeV9kaXNlYXNlKSkgKwogIHRoZW1lX2J3KCkgKwogIGdndGl0bGUoInRTTkUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoJ2ZvcmVzdGdyZWVuJywgJ3JlZDInKSkgLT50c25lX2V4cHJlc3Npb24KCmdnc2F2ZSgiL1VzZXJzL2Nhc3RpbGxuL0Rlc2t0b3AvdGhlc2lzL3RzbmVfZXhwcmVzc2lvbi5wbmciLCBkZXZpY2UgPSAicG5nIiwgd2lkdGggPSAzMCwgaGVpZ2h0ID0gMjUsIHVuaXRzID0gImNtIiwgZHBpID0gInJldGluYSIpCgpwcmludCh0c25lX2V4cHJlc3Npb24pCmBgYAoKCgoKCg==